﻿using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace GurLoader.View
{
    [ExcludeFromCodeCoverage]
    public class SelectionBackElement : FrameworkElement
    {
        public static readonly DependencyProperty ContainerProperty = DependencyProperty.Register("Container",
            typeof (FrameworkElement), typeof (SelectionBackElement),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure,
                new PropertyChangedCallback(OnContainerChanged)));

        public static readonly DependencyProperty AreaSelectedCommandProperty =
            DependencyProperty.Register("AreaSelectedCommand",
                typeof (ICommand), typeof (SelectionBackElement),
                new FrameworkPropertyMetadata());

        public static readonly DependencyProperty SelectionStartPointProperty =
            DependencyProperty.Register("SelectionStartPoint",
                typeof (Point), typeof (SelectionBackElement),
                new FrameworkPropertyMetadata());
        
        public static readonly DependencyProperty SelectionEndPointProperty =
            DependencyProperty.Register("SelectionEndPoint",
                typeof(Point), typeof(SelectionBackElement),
                new FrameworkPropertyMetadata());

        private DrawingVisual visual;
        private Boolean isDrawing;
        private Brush selectionBrush;
        private Pen selectionPen = new Pen(Brushes.Blue, 1);

        public SelectionBackElement()
        {
            Color color = SystemColors.HighlightColor;
            color.A = 128;
            selectionBrush = new SolidColorBrush(color);
            selectionPen = new Pen(SystemColors.HighlightBrush, 1);
            visual = new DrawingVisual();
            this.AddVisualChild(visual);
        }

        public Point SelectionStartPoint
        {
            get { return (Point) GetValue(SelectionStartPointProperty); }
            set { SetValue(SelectionStartPointProperty, value); }
        }

        public Point SelectionEndPoint
        {
            get { return (Point)GetValue(SelectionEndPointProperty); }
            set { SetValue(SelectionEndPointProperty, value); }
        }
        
        private static void OnContainerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SelectionBackElement sbe = d as SelectionBackElement;
            if (sbe == null)
                return;

            sbe.OnContainerChanged( e.OldValue as FrameworkElement, e.NewValue as FrameworkElement);
        }

        public void OnContainerChanged(FrameworkElement oldContainer, FrameworkElement newContainer)
        {
            if (oldContainer != null)
            {
                oldContainer.MouseDown -= MouseDownHandler;
                oldContainer.MouseMove -= MouseMoveHandler;
                oldContainer.MouseUp -= MouseUpHandler;
            }

            if (newContainer != null)
            {
                newContainer.MouseDown += MouseDownHandler;
                newContainer.MouseMove += MouseMoveHandler;
                newContainer.MouseUp += MouseUpHandler;
            }
        }

        public FrameworkElement Container
        {
            get { return (FrameworkElement) GetValue(ContainerProperty); }
            set { SetValue(ContainerProperty, value);}
        }

        public ICommand AreaSelectedCommand
        {
            get { return (ICommand) GetValue(AreaSelectedCommandProperty); }
            set { SetValue(AreaSelectedCommandProperty, value);}
        }

        protected override Int32 VisualChildrenCount
        {
            get { return 1; }
        }

        protected override Visual GetVisualChild(Int32 index)
        {
            return visual;
        }

        private void MouseDownHandler(Object sender, MouseButtonEventArgs e)
        {
            SelectionStartPoint = e.GetPosition(this);
            isDrawing = true;
        }

        private void MouseMoveHandler(Object sender, MouseEventArgs e)
        {
            if (isDrawing && e.LeftButton == MouseButtonState.Pressed)
            {
                SelectionEndPoint = e.GetPosition(this);
                DrawSelection(selectionBrush, selectionPen, SelectionStartPoint, SelectionEndPoint);
            }
        }

        private void MouseUpHandler(Object sender, MouseButtonEventArgs e)
        {
            isDrawing = false;
            FireAreaSelected();
        }

        private void FireAreaSelected()
        {
            if (AreaSelectedCommand != null)
            {
                if (AreaSelectedCommand.CanExecute(null))
                    AreaSelectedCommand.Execute(null);
            }
        }

        private void DrawSelection(Brush fill, Pen pen, Point startPoint, Point endPoint)
        {
            Vector vector = endPoint - startPoint;
            if (vector.Length > 10)
            {
                using (DrawingContext dc = visual.RenderOpen())
                {
                    dc.DrawGeometry(fill, pen, new RectangleGeometry(new Rect(startPoint, endPoint)));
                }
            }
        }
    }
}
